/*
* Copyright (c) 2007 by Kirill Kolodyazhniy.
* See the file "license.terms" for information on usage and redistribution.
*/

#ifndef M_DXRENDERSYSTEM_H
#define M_DXRENDERSYSTEM_H

#include "rendersystem.h"
#include "rendertargetvisitor.h"
#include "singleton.h"
#include "dxglobals.h"
#include "renderdata.h"

#include "dxheaders.h"

#include <vector>

namespace Engine
{

	class DXRenderWindow;

	/**
	*   Helper class to get buffer sutfaces from render targets
	*/
	class DXBuffersVisitor: public RenderTargetVisitor
	{
	public:

		void Visit(DXRenderWindow* window);

		IDirect3DSurface9* backBufferSurface;
		IDirect3DSurface9* zBufferSurface;
	};

	/**
	*  DirectX render system implementation.
	*/
	class DXRenderSystem: public RenderSystem, public Singleton<DXRenderSystem>
	{
		typedef std::vector<DXRenderWindow*> SecondaryWindowList;

	public:

		/**
		*   Constructor.
		*/
		DXRenderSystem();

		/**
		*   Destructor.
		*/
		~DXRenderSystem();

		/**
		*   Create new render window.
		*/
		virtual RenderWindowPtr CreateRenderWindow(const std::string& name, const PresentParams& pp);

		/**
		*   Clears one or more frame buffers on the active render target.
        *   @param buffers Combination of one or more elements of FrameBufferType denoting which buffers are to be cleared
        *   @param color The color to clear the color buffer with, if enabled
        *   @param depth The value to initialize the depth buffer with, if enabled
        *   @param stencil The value to initialize the stencil buffer with, if enabled.
        */
        virtual void ClearFrameBuffer(unsigned int buffers,
            const Color& color = Color::Black,
            REAL depth = 1.0, unsigned short stencil = 0);

		/**
		*   Set current render target for render to.
		*/
		virtual void SetRenderTarget(RenderTarget* renderTarget);

		/**
		*   Restore Direct3D device.
		*/
		void RestoreLostDevice();

		/**
		*   Tell system that Direct3D device is lost.
		*/
		void NotifyDeviceLost();

		/**
		*    Return true
		*/
		bool IsDeviceLost(){return m_deviceLost == true;}

		/**
		*   Begin scene rendering.
		*/
		virtual void BeginFrame();

		/**
		*   Finish scene rendering.
		*/
		virtual void EndFrame();

		/**
		*   Sets how to rasterise triangles, as points, wireframe or solid polys.
		*/
		virtual void SetPolygonMode(PolygonMode level);

		/**
		*   Sets the view transform matrix.
		*/
        virtual void SetViewMatrix(const Matrix4<REAL> &m);

        /**
		*   Sets the projection transform matrix.
		*/
        virtual void SetProjectionMatrix(const Matrix4<REAL> &m);

		/**
		*   Sets the world transform matrix.
		*/
        virtual void SetWorldMatrix(const Matrix4<REAL> &m);

		/**
		*   Set scene ambient light.
		*/
		virtual void SetAmbientLight(const Color& color);

		/**
		*   Setup lights for scene.
		*/
		virtual void UseLights(const LightVector& lights);

		/**
		*   Render geometries.
		*/
		virtual void Render(RenderDataPtr  renderData);

		/**
		*   Return directx specific data
		*/
		Direct3DGlobals* GetDirect3DGlobals(){return &m_direct3d;}

		/**
		*   Create index buffer.
		*/
		virtual RefPtr<HardWareBuffer,WeakPtrExtension> CreateIndexBuffer(unsigned int facecount, IndexType type);

		/**
		*   Create vertex buffer.
		*/
		virtual RefPtr<HardWareBuffer, WeakPtrExtension> CreateVertexBuffer(unsigned int vertexCount, unsigned int vertexSize);

		/**
		*   Create vertex declaration.
		*/
		virtual RefPtr<VertexDeclaration, WeakPtrExtension> CreateVertexDeclaration();

		/**
		*   Create render data for rendering API.
		*/
		virtual RefPtr<RenderData, WeakPtrExtension>  CreateRenderData(unsigned int faceCount, unsigned int vertexCount, VertexDeclarationPtr vertexDeclaration, HardWareBufferPtr indexData, HardWareBufferPtr vertexData, PrimitiveType primitiveType);


		//-----------------------------------Render specific methods-----------------------------------------
		virtual void SetDepthEnable(bool val);
		virtual void SetDepthWriteEnable(bool val);
		virtual void SetMaterial(const Color& ambientColor, const Color& diffuseColor, const Color& emissiveColor, const Color& specularColor , REAL power);
		virtual void SetShadeMode(ShadeMode val);
		virtual void SetCullMode(FaceCullMode val);
		virtual void SetLightingEnable(bool val);
		virtual void SetPointSpritesEnabled(bool enabled);
		virtual void SetPointParameters(REAL size, bool attenuationEnabled,REAL constant, REAL linear, REAL quadratic, REAL minSize, REAL maxSize);
		virtual void SetTexture(size_t unit,TexturePtr texPtr);
		virtual void SetTextureCoordSet(size_t unit, TexCoordCalcMethod m, size_t index);
		virtual void SetTextureBlendMode(size_t unit, const LayerBlendModeEx& bm);
		virtual void SetTextureUnitFiltering(size_t unit, FilterType ftype, FilterOptions filter);
		virtual unsigned int GetCurrentAnisotropy(size_t unit);
		virtual void SetTextureLayerAnisotropy(size_t unit, unsigned int maxAnisotropy);
		virtual void SetTextureAddressingMode(size_t unit, const UVWAddressingMode& uvw);
		virtual void SetTextureBordercolor(size_t unit, const Color& color);
		virtual void SetTextureMipmapBias(size_t unit, REAL bias);
		virtual void SetTextureMatrix(size_t unit, const Matrix4<REAL>& xform, TexCoordDim texCoordDim);
		virtual void SetSceneBlending(SceneBlendFactor sourceFactor, SceneBlendFactor destFactor);
		virtual void SetAlphaRejectSettings(CompareFunction func, unsigned char value);
		virtual void SetDepthBufferFunction(CompareFunction func);
		virtual void SetColorBufferWriteEnabled(bool red, bool green, bool blue, bool alpha);
		virtual void SetDepthBias(REAL constantBias, REAL slopeScaleBias);
		virtual void SetFog(FogMode mode, const Color& color , REAL expDensity, REAL linearStart, REAL linearEnd );
		virtual void SetStencilCheckEnabled(bool enabled);
		virtual void SetStencilBufferParams(CompareFunction func ,unsigned int refValue, unsigned int mask,StencilOperation stencilFailOp ,StencilOperation depthFailOp,StencilOperation passOp,bool twoSidedOperation);
		virtual void SetNormaliseNormals(bool normalise);
		virtual void SetClipPlane (unsigned short index, REAL A, REAL B, REAL C, REAL D);
		virtual void SetEenableClipPlane (unsigned short index, bool enable);
		virtual void SetScissorTest(bool enabled, size_t left, size_t top,size_t right, size_t bottom);
		//---------------------------------------------------------------------------------------------------

	private:

		/**
		*   Set hw light parameters from input specification.
		*/
		void SetD3D9Light( size_t index, const Light* lt );

		/**
		*   Cached version of direct3d fuction.
		*/
		HRESULT SetRenderState(D3DRENDERSTATETYPE state, DWORD value);
		HRESULT SetTextureStageState(DWORD Stage, D3DTEXTURESTAGESTATETYPE Type, DWORD Value);
		HRESULT SetSamplerState( DWORD Sampler, D3DSAMPLERSTATETYPE Type, DWORD Value);

	private:

		Direct3DGlobals m_direct3d; ///< Set of direct3d common objects.

		bool m_deviceLost;

		// List of additional windows after the first (swap chains)
		SecondaryWindowList m_secondaryWindows;

		DXRenderWindow* m_primaryWindow;

		LightVector::size_type m_currentLights; //num directx light index used in scene

		Color m_manualBlendColours[8][2];
	};

	/**
	*   Factory for creating directx render system objects.
	*/
	class DXRenderSystemFactory: public RenderSystemFactory
	{
	public:

		DXRenderSystemFactory():m_type("DirectXRenderSystem"){}

		/**
		*   Returns the factory type.
		*/
		virtual const std::string& GetType() const {return m_type;}

		/**
		*   Creates a new object.
		*   @param name Name of the object to create
		*   @return	An object created by the factory. The type of the object depends on	the factory.
		*/
		virtual RenderSystem* CreateInstance( const std::string& );

	private:

		std::string m_type;
	};
}

#endif

